home *** CD-ROM | disk | FTP | other *** search
/ Archive Magazine CD 1995 / Archive Magazine CD 1995.iso / discs / prog_disc / volume_5 / issue_08 / boota / C-source / c / GetDirs < prev    next >
Encoding:
Text File  |  1991-12-16  |  45.1 KB  |  1,006 lines

  1. /* > c.GetDirs   - (c) Paul Witheridge - Version 2.00 - 07 Dec 1991  */
  2.  
  3. /*===================================================================*/
  4. /*                                                                   */
  5. /*  Getdirentrys                                                     */
  6. /*  ------------                                                     */
  7. /*                                                                   */
  8. /*  Getdirentrys is a function which reads entries from a directory  */
  9. /*  and then invokes a caller-supplied function to process each      */
  10. /*  file-object, passing the directory entry details in a 'direntry' */
  11. /*  structure defined in 'getdirs.h'.                                */ 
  12. /*                                                                   */ 
  13. /*  The caller supplies the name of the directory to be read (plus   */
  14. /*  optionally, a wildcarded or non-wildcarded object name to be     */
  15. /*  matched against objects in the directory), an indicator as to    */
  16. /*  whether any subdirectories found should be read (recursively)    */
  17. /*  and a pointer to the caller's function to process the entries.   */
  18. /*                                                                   */
  19. /*  The global integer variable "getdirentrys_counter" counts the    */
  20. /*  the number of objects passed to the caller's function.           */
  21. /*                                                                   */
  22. /*  The caller's function should return a value of 'TRUE' if it has  */
  23. /*  not encountered any fatal errors, or 'FALSE' if it wants to      */
  24. /*  stop processing of any further directory entries.                */
  25. /*                                                                   */
  26. /*-------------------------------------------------------------------*/
  27. /*                                                                   */
  28. /*  This file includes the following functions:                      */
  29. /*                                                                   */
  30. /*       getdirentrys   -  read and process directory entries        */
  31. /*       buildtree      -  internal (static) recursive function      */
  32. /*       processtree    -  internal (static) recursive function      */
  33. /*       extendpath     -  internal (static) function                */
  34. /*       freetree       -  internal (static) recursive function      */
  35. /*       beep           -  sound two tone beep                       */
  36. /*                                                                   */
  37. /*-------------------------------------------------------------------*/
  38. /*                                                                   */
  39. /*  COPYRIGHT NOTICE                                                 */
  40. /*                                                                   */
  41. /*  GetDirs is subject to Copyright.                                 */
  42. /*                                                                   */
  43. /*  Permission is granted by the author to any recipient of this     */
  44. /*  material to use and make/disseminate copies of the application   */
  45. /*  provided that no charges are made for doing so (other than to    */
  46. /*  cover any cost of media or postage) and that this notice is      */
  47. /*  included with all copies.                                        */
  48. /*                                                                   */
  49. /*===================================================================*/
  50.  
  51. #include "kernel.h"                   /* ARC specifics               */
  52. #include <ctype.h>                    /* Character handling          */
  53. #include <limits.h>                   /* Implementation limits       */
  54. #include <stddef.h>                   /* Standard defintions         */
  55. #include <stdio.h>                    /* Input/output                */
  56. #include <stdlib.h>                   /* General utilities           */
  57. #include <string.h>                   /* String handling             */
  58.  
  59. #include "getdirs.h"                  /* GetDirs header              */
  60. #include "useful.h"                   /* Useful defns                */
  61.  
  62. /*-------------------------------------------------------------------*/
  63. /* Global data declarations and definitions.                         */
  64. /*-------------------------------------------------------------------*/
  65.  
  66. #define maxpathlen     255            /* Max path length             */
  67. #define maxobjectlen    20            /* Max object length           */
  68. #define maxdirlistlen 1024            /* Max directory list length   */
  69.  
  70. struct dirblock                       /* Directory list structure    */
  71. {
  72.   struct dirblock *subdirq ;          /* Ptr to subdirectory tree    */
  73.   struct dirblock *nextptr ;          /* Ptr to next list            */
  74.   int nobjects ;                      /* No. of objects in this list */
  75.   int handle ;                        /* Handle (id) for this list   */
  76.   char dirlist[maxdirlistlen] ;       /* List of nul-term'd objects  */
  77. } ;
  78.  
  79. int getdirentrys_counter ;            /* Count of files processed    */
  80.  
  81. static enum boolean (*funcptr)(       /* Ptr to function             */
  82.   const char *path,
  83.   direntry *ptr) ;
  84.  
  85. static const char toolong[] =         /* Common error message        */
  86.   "'%s' too long" ;
  87.  
  88. static const char outofmemory[] =     /* Common error message        */
  89.   "out of memory" ;
  90.  
  91. static const char invalidentry[] =    /* Common error message        */
  92.   "Invalid directory entry '%s'\n" ;
  93.  
  94. /*-------------------------------------------------------------------*/
  95. /*  Declare functions local in scope to this file.                   */
  96. /*-------------------------------------------------------------------*/
  97.  
  98. static enum boolean buildtree(        /* Build directory list tree   */
  99.   char *path,
  100.   const char *object,
  101.   const enum recursive recursion,
  102.   const int handle,
  103.   struct dirblock **subdirq) ;
  104.  
  105. static enum boolean processtree(      /* Process directory list tree */
  106.   char *path,
  107.   struct dirblock *dirblkptr) ;
  108.  
  109. static enum boolean extendpath(       /* Add leafname to path        */
  110.   char *path,
  111.   int pathlen,
  112.   const char *leafname) ;
  113.  
  114. static void freetree(                 /* Free directory list tree    */
  115.   struct dirblock **subdirq) ;
  116.  
  117. /*===================================================================*/
  118. /*                                                                   */
  119. /* getdirentrys  -  read directory entries                           */
  120. /* ------------                                                      */
  121. /*                                                                   */
  122. /* This function is called to read entries from a caller-specified   */
  123. /* directory and pass details of any entries for file objects to a   */
  124. /* caller-supplied function. It is intended for use with a non       */
  125. /* multitasking utility, since it may write error messages to the    */
  126. /* standard output stream.                                           */
  127. /*                                                                   */
  128. /* The caller provides three arguments:                              */
  129. /*                                                                   */
  130. /* (1) Directory name and optional object name. This may be a fully  */
  131. /*     qualified name (e.g. 'adfs::IDEDisc4.$.Clib.h') or it may be  */
  132. /*     relative to the currently selected directory (e.g. just 'h'   */
  133. /*     if the CSD is 'adfs::IDEDisc4.$.Clib' or '^.h' if the CSD is  */
  134. /*     'adfs::IDEDisc4.$.Clib.o'). It may end with a wild-carded or  */
  135. /*     non-wildcarded object name which will be used to select       */
  136. /*     objects from the director (e.g. 'h.a*' meaning all file       */
  137. /*     objects beginning with 'a' in directory 'h' which is a sub-   */
  138. /*     directory of the CSD).                                        */
  139. /*                                                                   */
  140. /* (2) A switch indicating whether any subdirectories found in the   */
  141. /*     specified directory are to be processed or not. This can take */
  142. /*     one of three values 'RECURSE_NEVER', 'RECURSE_ONCE' or        */
  143. /*     'RECURSE_ALWAYS'. These are defined in 'getdirs.h'. They have */
  144. /*     the following effect:                                         */
  145. /*                                                                   */
  146. /*     RECURSE_NEVER implies that the caller knows that the first    */
  147. /*     argument is in the form 'directory.object', and that object   */
  148. /*     is a (possibly wildcarded) file leafname. Only file objects   */
  149. /*     in 'directory' are to be processed; any subdirectories are    */
  150. /*     to be ignored. So if 'object' turned out to be a directory    */
  151. /*     name it would be ignored. This value would only be used under */
  152. /*     special circumstances.                                        */
  153. /*                                                                   */
  154. /*     RECURSE_ONCE implies that the caller is unsure whether the    */
  155. /*     first argument is in the form 'directory.object' or just      */
  156. /*     'directory'. If it turns out to be a directory, then all the  */
  157. /*     file objects in that directory are to be processed, but any   */
  158. /*     subdirectories are to be ignored. This would be the normal    */
  159. /*     value to use if subdirectories were not to be processed.      */
  160. /*                                                                   */
  161. /*     RECURSE_ALWAYS implies full recursion. All files matching     */
  162. /*     'object' found in directory will be processed. All sub-       */
  163. /*     directories matching 'object' will be read; all files in them */
  164. /*     will be processed and all subdirectories found will be read   */
  165. /*     recursively.                                                  */
  166. /*                                                                   */
  167. /* (3) A pointer to a function which will process the file-objects.  */
  168. /*     It will be called once for each file-object found in the      */
  169. /*     specified directory (and all subdirectories if argument 2     */
  170. /*     specifies recursive processing of subdirectories). It is      */
  171. /*     passed the name of the directory and a pointer to the details */
  172. /*     from the directory in a 'direntry' structure. These details   */
  173. /*     include the object-name, its load and exec addresses (which   */
  174. /*     may be in the form of file-type and time-stamp), its length,  */
  175. /*     and its attributes. The file-type is extracted from the load  */
  176. /*     address and supplied separately (or as 0xFFFFFFFF if the file */
  177. /*     has no file-type and time-stamp). This function should return */
  178. /*     a value of 'FALSE' to halt further processing, or 'TRUE' to   */
  179. /*     continue processing of the directory entries.                 */
  180. /*                                                                   */
  181. /* Getdirentrys returns a value of TRUE if it encountered no errors  */
  182. /* in reading the directory entries and if the caller-supplied       */
  183. /* function always returns 'TRUE'. Getdirentrys returns a value of   */
  184. /* 'FALSE' if it encountered any errors reading the directory, or if */
  185. /* the caller-supplied function returned a value of FALSE. The       */
  186. /* values 'TRUE' and 'FALSE' are defined in 'useful.h'.              */
  187. /*                                                                   */
  188. /* Two passes are made through the directory (and subdirectories if  */
  189. /* recursive processing required). The first pass is performed by    */
  190. /* calling the internal function 'buildtree' which creates a tree    */
  191. /* of 'dirlist' structures listing the current contents of the       */
  192. /* directories. The second pass is performed by calling the internal */
  193. /* function 'processtree' which checks that each file-object in the  */
  194. /* tree structure is still present, and if so invokes the caller-    */
  195. /* supplied function.                                                */
  196. /*                                                                   */
  197. /* The two passes are made in this way so that the caller-supplied   */
  198. /* function is only invoked for objects that already exist, and not  */
  199. /* for any objects that the caller-supplied function may create.     */
  200. /* Otherwise, potentially infinite loops could occur - not really    */
  201. /* infinite because they would stop when directory of disk full      */
  202. /* conditions occurred.                                              */
  203. /*                                                                   */
  204. /* The internal function 'freetree' is used to free up the memory    */
  205. /* allocated to the tree structure.                                  */
  206. /*                                                                   */
  207. /* The counter 'getdirentrys_counter' is used to count the number of */
  208. /* times the caller-supplied function is invoked. This count is      */
  209. /* available (as an external variable) to the original caller of     */
  210. /* 'getdirentrys' when thus returns.                                 */
  211. /*                                                                   */
  212. /*===================================================================*/
  213.  
  214. enum boolean getdirentrys(
  215.   const char *fname,                  /* Ptr to initial name         */
  216.   const enum recursive recursion,     /* Recursion switch            */
  217.   enum boolean (*func)(               /* Ptr to function             */
  218.     const char *path,
  219.     direntry *ptr))
  220. {
  221.   /*-----------------------------------------------------------------*/
  222.   /* Local definitions.                                              */
  223.   /*-----------------------------------------------------------------*/
  224.  
  225.   char *p ;                           /* Working pointer             */
  226.   int pathlen ;                       /* Path length                 */
  227.   struct dirblock *dirblkptr ;        /* Ptr to directory tree       */
  228.   enum boolean result ;               /* Value to be returned        */
  229.   char path[maxpathlen+1] ;           /* Path work area              */
  230.   char object[maxobjectlen+1] ;       /* Object work area            */
  231.   static char asterisk[] = "*" ;      /* Default object              */
  232.   static const char specials[] =      /* Special directory letters   */
  233.     "@$^\\&%" ;
  234.  
  235.   /*-----------------------------------------------------------------*/
  236.   /* Executable statements                                           */
  237.   /*                                                                 */
  238.   /* First zero counter in case of immediate exit.                   */
  239.   /*-----------------------------------------------------------------*/
  240.   
  241.   getdirentrys_counter = 0 ;
  242.  
  243.   /*-----------------------------------------------------------------*/
  244.   /* Copy argument "fname" to variable "path" where it can be worked */
  245.   /* on. Strip leading blanks and quotes; then copy up to, but not   */
  246.   /* including, first blank or quote (or to end of string). Take     */
  247.   /* FALSE exit immediately if it is too long.                       */
  248.   /*-----------------------------------------------------------------*/
  249.   
  250.   if ( strlen(fname) > maxpathlen - 3 )
  251.   {
  252.     printf(toolong,fname) ;
  253.     beep() ;
  254.     return FALSE ;
  255.   }
  256.  
  257.   strcpy(path,fname + strspn(fname," \"")) ;
  258.   pathlen = strcspn(path," \"") ;
  259.   path[pathlen] = '\0' ;
  260.  
  261.   /*-----------------------------------------------------------------*/
  262.   /* If argument is null then default to current directory.          */
  263.   /*-----------------------------------------------------------------*/
  264.   
  265.   if ( pathlen == 0 )
  266.   {
  267.     strcpy(path,"@") ;
  268.     pathlen = 1 ;
  269.   } 
  270.  
  271.   /*-----------------------------------------------------------------*/
  272.   /* If argument incorporates any periods, split into path and       */
  273.   /* object at last period.                                          */
  274.   /*-----------------------------------------------------------------*/
  275.  
  276.   if ( ( p = strrchr(path,'.') ) != NULL )
  277.   {
  278.     pathlen = p - path ;
  279.     p++ ;
  280.   }
  281.  
  282.   /*-----------------------------------------------------------------*/
  283.   /* If no period, check for a colon which could be either end of a  */
  284.   /* filing system name or start of a disk name.                     */
  285.   /*                                                                 */
  286.   /* If just name of a filing system (e.g. adfs:) then add "@" and   */
  287.   /* set object to "*".                                              */
  288.   /*                                                                 */
  289.   /* If filing system name plus special directory letter or disk     */
  290.   /* name (e.g. adfs:@ or adfs::IDEDisk4) then just set object to    */
  291.   /* "*".                                                            */
  292.   /*                                                                 */
  293.   /* If filing system name plus object name (e.g. adfs:myfile) then  */
  294.   /* split into path and object just after ":" and add "@" to the    */
  295.   /* filing system name.                                             */
  296.   /*-----------------------------------------------------------------*/
  297.  
  298.   else if ( ( p = strchr(path,':') ) != NULL )
  299.   {
  300.     p++ ;
  301.     if ( *p == '\0' )
  302.     {
  303.       path[pathlen++] = '@' ;
  304.       p = asterisk ;
  305.     }
  306.     else if ( ( *(p + 1) == '\0' && strchr(specials,*p) != NULL ) ||
  307.               ( *p == ':' ) )
  308.     {
  309.       p = asterisk ;
  310.     }
  311.     else
  312.     {
  313.       memmove(p + 1,p,strlen(p) + 1) ;
  314.       *p = '@' ;
  315.       p++ ;
  316.       pathlen = p - path ;
  317.     }
  318.   }
  319.  
  320.   /*-----------------------------------------------------------------*/
  321.   /* No period or colon found.                                       */
  322.   /*                                                                 */
  323.   /* If argument is just a directory letter (e.g. @ or $) then just  */
  324.   /* set object to "*".                                              */
  325.   /*                                                                 */
  326.   /* Otherwise treat entire argument as the object name and set the  */
  327.   /* path to "@".                                                    */
  328.   /*-----------------------------------------------------------------*/
  329.  
  330.   else
  331.  {
  332.     if ( pathlen == 1 && strchr(specials,path[0]) != NULL )
  333.     {
  334.       p = asterisk ;
  335.     }
  336.     else
  337.     {
  338.       p = path + 1 ;
  339.       memmove(p,path,strlen(path) + 1) ;
  340.       *p = '@' ;
  341.       pathlen = 1 ;
  342.     }
  343.   }
  344.  
  345.   /*-----------------------------------------------------------------*/
  346.   /* Copy the object to variable "object" and store terminating nul  */
  347.   /* at end of the path. Take FALSE exit if the object name is too   */
  348.   /* long.                                                           */
  349.   /*-----------------------------------------------------------------*/
  350.  
  351.   if ( strlen(p) > maxobjectlen )
  352.   {
  353.     printf(toolong,p) ;
  354.     beep() ;
  355.     return FALSE ;
  356.   }
  357.   strcpy(object,p) ;
  358.   
  359.   path[pathlen] = '\0' ;
  360.  
  361.   /*-----------------------------------------------------------------*/
  362.   /* Copy function pointer to global variable (to avoid need to pass */
  363.   /* same value on when recursing). Set anchor word for directory    */
  364.   /* list tree to NULL. Then invoke buildtree to create directory    */
  365.   /* list tree and processtree to process the entries in the tree.   */
  366.   /*-----------------------------------------------------------------*/
  367.  
  368.   funcptr = func ;
  369.   dirblkptr = NULL ;
  370.  
  371.   if ( ( result = buildtree(path,object,recursion,0,&dirblkptr) ) == TRUE )
  372.   {
  373.     if ( dirblkptr != NULL )
  374.     {
  375.       result = processtree(path,dirblkptr) ;
  376.       freetree(&dirblkptr) ;
  377.     }
  378.   }
  379.  
  380.   /*-----------------------------------------------------------------*/
  381.   /*  Return to caller.                                              */
  382.   /*-----------------------------------------------------------------*/
  383.  
  384.   return result ;
  385. }
  386.  
  387. /*===================================================================*/
  388. /*                                                                   */
  389. /* buildtree  -  build tree of directory entry lists                 */
  390. /* ---------                                                         */
  391. /*                                                                   */
  392. /* This function is called to create a list of entries in the        */
  393. /* target directory that match a (possibly wildcarded) object name.  */
  394. /* This function will also invoke itself recursively, if required,   */
  395. /* to process subdirectories.                                        */
  396. /*                                                                   */
  397. /* The caller provides as arguments:                                 */
  398. /*                                                                   */
  399. /*   path      -  the name of the directory to be searched, must     */
  400. /*                include the path (if any) and leafname             */
  401. /*                                                                   */
  402. /*   object    -  wildcarded object name used in selecting directory */
  403. /*                entries                                            */
  404. /*                                                                   */
  405. /*   recursion -  switch indicating if matching files only are to be */
  406. /*                processed (RECURSE_NEVER), or first dirctory if no */
  407. /*                matching files found (RECURSE_ONCE), or all        */
  408. /*                matching files and directives are to be processed  */
  409. /*                recursively (RECURSE_ALWAYS)                       */
  410. /*                                                                   */
  411. /*   handle    -  identifier used later to identify this entry       */ 
  412. /*                                                                   */
  413. /*   subdirq   -  pointer to anchor word on which to queue the       */
  414. /*                directory list if it is successfully built.        */
  415. /*                                                                   */
  416. /* If the function completes successfully, it returns a value of     */
  417. /* TRUE (and if any matching directory entries were found, it queues */
  418. /* the directory list it has built off the anchor word provided by   */
  419. /* the caller).                                                      */
  420. /*                                                                   */
  421. /* If an error is encountered, it returns FALSE. In this case no     */
  422. /* directory list is built.                                          */
  423. /*                                                                   */
  424. /*===================================================================*/
  425.  
  426. static enum boolean buildtree(
  427.   char *path,                         /* Directory path              */
  428.   const char *object,                 /* Object (wildcarded)         */
  429.   const enum recursive recursion,     /* Recursion switch            */
  430.   int handle,                         /* Id provided by caller       */
  431.   struct dirblock **subdirq)          /* Ptr to subdir queue anchor  */
  432. {
  433.   /*-----------------------------------------------------------------*/
  434.   /* Local definitions                                               */
  435.   /*-----------------------------------------------------------------*/
  436.  
  437.   int pathlen ;                       /* Length of path string       */
  438.   int found ;                         /* Found switch                */
  439.   int i ;                             /* Working integer             */
  440.   char *dataptr ;                     /* Working pointer             */
  441.   struct dirblock *dirblkptr ;        /* Directory list block ptr    */
  442.   struct dirblock *dirwrkptr ;        /* Working dir list block ptr  */
  443.   _kernel_osgbpb_block gbpbblk ;      /* OS_GBPG parameter block     */
  444.   _kernel_osfile_block fileblk ;      /* OS_File parameter block     */
  445.  
  446.   /*-----------------------------------------------------------------*/
  447.   /* Executable statements                                           */
  448.   /*                                                                 */
  449.   /* First save length of path on entry so that path can be          */
  450.   /* truncated again to this length on exit. Also set found flag to  */
  451.   /* value of FALSE (it will be set to TRUE later if any files found */
  452.   /* to process.                                                     */
  453.   /*-----------------------------------------------------------------*/
  454.  
  455.   pathlen = strlen(path) ;
  456.   found   = FALSE ;
  457.  
  458.   /*-----------------------------------------------------------------*/
  459.   /* Next allocate memory for table of directory names. Take FALSE   */
  460.   /* exit if unable to do so. Otherwise initialise control fields at */
  461.   /* head of table: number of names in table set to zero, anchor     */
  462.   /* field for subdirectory queue and chain pointer used to queue    */
  463.   /* block off parent table are set to null, and handle provided by  */
  464.   /* caller store in header.                                         */
  465.   /*-----------------------------------------------------------------*/
  466.  
  467.   if ( ( dirblkptr = malloc(sizeof(struct dirblock)) ) == NULL )
  468.   {
  469.     puts(outofmemory) ;
  470.     beep() ;
  471.     goto badbuild3 ;
  472.   }
  473.   dirblkptr->nobjects = 0 ;
  474.   dirblkptr->subdirq  = dirblkptr->nextptr = NULL ;
  475.   dirblkptr->handle   = handle ;
  476.  
  477.   /*-----------------------------------------------------------------*/
  478.   /* Use OS_GBPB to read list of names in directory that match the   */
  479.   /* (possibly wildcarded) object name provided by the caller. This  */
  480.   /* is done as a repetitive process until an OS_GBPB indicates that */
  481.   /* no more entries remain (probably only ever go through loop once */
  482.   /* but the RICS-OS PRM states that not all filing systems may be   */
  483.   /* able to do it in one go). If zero entries are obtained but the  */
  484.   /* returned values indicate that the end of the directory has not  */
  485.   /* been reached, then the buffer is full. In this case issue an    */
  486.   /* error message and go take the FALSE exit                        */
  487.   /*-----------------------------------------------------------------*/
  488.  
  489.   gbpbblk.dataptr  = dirblkptr->dirlist ;
  490.   dataptr          = dirblkptr->dirlist + sizeof(dirblkptr->dirlist) ;
  491.   gbpbblk.fileptr  = 0 ;
  492.   gbpbblk.wild_fld = (char *)object ;
  493.  
  494.   do
  495.   {
  496.     gbpbblk.nbytes  = INT_MAX ;
  497.     gbpbblk.buf_len = dataptr - (char *)gbpbblk.dataptr ;
  498.     if ( _kernel_osgbpb(9,(unsigned)path,&gbpbblk) == _kernel_ERROR )
  499.     {
  500.       printf("%s\n",_kernel_last_oserror()->errmess) ;
  501.       goto badbuild1 ;
  502.     }
  503.     for ( i = 0 ; i < gbpbblk.nbytes ; i++ )
  504.     {
  505.       gbpbblk.dataptr = (char *)gbpbblk.dataptr +
  506.                         strlen((char *)gbpbblk.dataptr) + 1 ;
  507.     }
  508.     dirblkptr->nobjects += gbpbblk.nbytes ;
  509.     if ( gbpbblk.fileptr == -1 )
  510.     {
  511.       break ;
  512.     }
  513.     if ( gbpbblk.nbytes == 0 )
  514.     {
  515.       printf("Too many objects in directory %s\n",path) ;
  516.       goto badbuild1 ;
  517.     }
  518.   } FOREVER ;
  519.  
  520.   /*-----------------------------------------------------------------*/
  521.   /* If no matching entries found in the directory, go take TRUE     */
  522.   /* exit immediately (which will cause directory list block to be   */
  523.   /* freed instead of queued because found flag is not set).         */
  524.   /*-----------------------------------------------------------------*/
  525.  
  526.   if ( dirblkptr->nobjects == 0 )
  527.   {
  528.     goto goodbuild ;
  529.   }
  530.  
  531.   /*-----------------------------------------------------------------*/
  532.   /* Otherwise free unused space at end of the directory list block. */
  533.   /* Allow for possible NULL return from realloc although it does    */
  534.   /* not seem likely since we are shortening the block.              */
  535.   /*-----------------------------------------------------------------*/
  536.  
  537.   dirwrkptr = realloc(dirblkptr,offsetof(struct dirblock,dirlist) +
  538.                       (char *)gbpbblk.dataptr - dirblkptr->dirlist) ;
  539.   if ( dirwrkptr != NULL )
  540.   {
  541.     dirblkptr = dirwrkptr ;
  542.   }
  543.  
  544.   /*-----------------------------------------------------------------*/
  545.   /* Loop through list of directory entries checking which ones are  */
  546.   /* files and which ones are subdirectories using OS_File type 13   */
  547.   /* to read the catalog details for each object (note: a period     */
  548.   /* must be added to the end of the path for OS_File).              */
  549.   /*-----------------------------------------------------------------*/
  550.  
  551.   for ( i = 0 , dataptr = dirblkptr->dirlist ;
  552.         i < dirblkptr->nobjects ;
  553.         i++ , dataptr += strlen(dataptr) + 1 )
  554.   { 
  555.     strcpy(path + pathlen,".") ;
  556.     fileblk.start = (int)path ;
  557.     switch ( _kernel_osfile(13,dataptr,&fileblk) )
  558.     {
  559.       /*-------------------------------------------------------------*/
  560.       /* Returned value = 1 (file found). Set file found flag.       */
  561.       /*-------------------------------------------------------------*/
  562.  
  563.       case 1  :
  564.  
  565.         found = TRUE ;
  566.         break ;
  567.  
  568.       /*-------------------------------------------------------------*/
  569.       /* Returned value = 2 (directory found). If recursion always   */
  570.       /* required, call ouselves recursively to build directory list */
  571.       /* block for the subdirectory. If not just skip the directory. */
  572.       /*-------------------------------------------------------------*/
  573.  
  574.       case 2  :
  575.  
  576.         if ( recursion == RECURSE_ALWAYS )
  577.         {
  578.           if ( !extendpath(path,pathlen,dataptr) )
  579.           {
  580.             goto badbuild2 ;
  581.           }
  582.           if ( !buildtree(path,"*",RECURSE_ALWAYS,
  583.                           (int)dataptr,&dirblkptr->subdirq) )
  584.           {
  585.             goto badbuild2 ;
  586.           }
  587.         }
  588.         break ;
  589.  
  590.       /*-------------------------------------------------------------*/
  591.       /* Returned value = -2 (error occurred). Display error message */
  592.       /* and go take FALSE exit.                                     */
  593.       /*-------------------------------------------------------------*/
  594.  
  595.       case _kernel_ERROR :
  596.  
  597.         printf("%s\n",_kernel_last_oserror()->errmess) ;
  598.         goto badbuild1 ;
  599.  
  600.       /*-------------------------------------------------------------*/
  601.       /* Other value should not occur. Being paranoid, if they do    */
  602.       /* just display a message and go take FALSE exit.              */
  603.       /*-------------------------------------------------------------*/
  604.  
  605.       default :
  606.  
  607.         printf(invalidentry,dataptr) ;
  608.         goto badbuild1 ;
  609.     }
  610.     
  611.     /*---------------------------------------------------------------*/
  612.     /* Truncate path to original length.                             */
  613.     /*---------------------------------------------------------------*/
  614.  
  615.     path[pathlen] = '\0' ;
  616.   }
  617.  
  618.   /*-----------------------------------------------------------------*/
  619.   /* If no files were found then all the entries must have been for  */
  620.   /* subdirectories. If blanket recursion (RECURSE_ALWAYS) was not   */
  621.   /* required, none of them were processed. If RECURSE_ONCE was      */
  622.   /* specified, process the first entry only by invoking ourselves   */
  623.   /* recursively (but prevent any deeper recursion by specifying     */
  624.   /*-----------------------------------------------------------------*/
  625.  
  626.   if ( !found && recursion == RECURSE_ONCE )
  627.   {
  628.     dirblkptr->nobjects = 1 ;
  629.     dirwrkptr = realloc(dirblkptr,offsetof(struct dirblock,dirlist) +
  630.                                   strlen(dirblkptr->dirlist) + 1) ;
  631.     if ( dirwrkptr != NULL )
  632.     {
  633.       dirblkptr = dirwrkptr ;
  634.     }
  635.     if ( !extendpath(path,pathlen,dirblkptr->dirlist) )
  636.     {
  637.       goto badbuild2 ;
  638.     }
  639.     if ( !buildtree(path,"*",RECURSE_NEVER,(int)dirblkptr->dirlist,
  640.                     &dirblkptr->subdirq) )
  641.     {
  642.       goto badbuild2 ;
  643.     }
  644.     path[pathlen] = '\0' ;
  645.   }
  646.  
  647.   /*-----------------------------------------------------------------*/
  648.   /* Arrive here to take TRUE exit to caller indicating that no      */
  649.   /* error occurred. If no files were found and no subdirectory      */
  650.   /* lists queued, just free the directory list block. Otherwise     */
  651.   /* queue it off the caller's subdirectory queue.                   */
  652.   /*-----------------------------------------------------------------*/
  653.  
  654.   goodbuild:
  655.  
  656.     if ( !found && dirblkptr->subdirq == NULL )
  657.     {
  658.       free(dirblkptr) ;
  659.     }
  660.     else
  661.     {
  662.       dirblkptr->nextptr = *subdirq ;
  663.       *subdirq = dirblkptr ;
  664.     }
  665.     return TRUE ;
  666.  
  667.   /*-----------------------------------------------------------------*/
  668.   /* Arrive here when error occurs to take FALSE exit to caller.     */
  669.   /*-----------------------------------------------------------------*/
  670.  
  671.   badbuild1:
  672.  
  673.     beep() ;
  674.  
  675.   badbuild2:
  676.  
  677.     freetree(&dirblkptr->subdirq) ;
  678.     free(dirblkptr) ;
  679.  
  680.   badbuild3:
  681.  
  682.     path[pathlen] = '\0' ;
  683.     return FALSE ;
  684. }
  685.  
  686. /*===================================================================*/
  687. /*                                                                   */
  688. /* processtree  -  process files in directory list                   */
  689. /* -----------                                                       */
  690. /*                                                                   */
  691. /* This function processes all the files listed in the tree of       */
  692. /* directory lists created by buildtree, by caller a processing      */
  693. /* function pointed to by global variable "funcptr" for each file in */
  694. /* turn. It calls itself recursively to handle subdirectories.       */
  695. /*                                                                   */
  696. /* The caller provides two arguments:                                */
  697. /*                                                                   */
  698. /*   path       -  name of the directory including path (if any) and */
  699. /*                 leaf-name.                                        */
  700. /*                                                                   */
  701. /*   dirblkptr  -  list of entries in the directory to be processed  */
  702. /*                                                                   */
  703. /*===================================================================*/
  704.  
  705. static enum boolean processtree(
  706.   char *path,                         /* Ptr to path                 */
  707.   struct dirblock *dirblkptr)         /* Ptr to directory block      */
  708. {
  709.   /*-----------------------------------------------------------------*/
  710.   /* Local definitions.                                              */
  711.   /*-----------------------------------------------------------------*/
  712.  
  713.   int pathlen ;                       /* Length of path string       */
  714.   int i ;                             /* Working integer             */
  715.   char *dataptr ;                     /* Working pointer             */
  716.   struct dirblock *dirwrkptr ;        /* Working dir list block ptr  */
  717.   _kernel_osfile_block fileblk ;      /* OS_File parameter block     */
  718.   direntry direntryblk ;              /* Directory entry data        */
  719.  
  720.   /*-----------------------------------------------------------------*/
  721.   /* Executable statements                                           */
  722.   /*                                                                 */
  723.   /* First save current path length so that path can be truncated    */
  724.   /* to original length after being extending for recursion.         */
  725.   /*-----------------------------------------------------------------*/
  726.  
  727.   pathlen = strlen(path) ;
  728.  
  729.   /*-----------------------------------------------------------------*/
  730.   /* Loop through entries in the directory list invoking OS_File to  */
  731.   /* read catalog information for the object.                        */
  732.   /*-----------------------------------------------------------------*/
  733.  
  734.   for ( i = 0 , dataptr = dirblkptr->dirlist ;
  735.         i < dirblkptr->nobjects ;
  736.         i++ , dataptr += strlen(dataptr) + 1 )
  737.   {
  738.     strcpy(path + pathlen,".") ;
  739.     fileblk.start = (int)path ;
  740.     switch ( _kernel_osfile(13,dataptr,&fileblk) )
  741.     {
  742.       /*-------------------------------------------------------------*/
  743.       /* Returned value = 0 (not found). This is unlikely, but could */
  744.       /* occur if the processing function provided by the caller     */
  745.       /* gets up to very funny tricks. Issue message and ignore.     */
  746.       /*-------------------------------------------------------------*/
  747.  
  748.       case 0  :
  749.  
  750.         printf("'%s.%s' not found\n",path,dataptr) ;
  751.  
  752.         break ;
  753.  
  754.       /*-------------------------------------------------------------*/
  755.       /* Returned value = 1 (file). Bump number of files found and   */
  756.       /* copy catalog information into a direntry structure (defined */
  757.       /* in "getdirs.h"). Extract file-type as convenience for the   */
  758.       /* processing function (or use -1 if not file-typed). Then     */
  759.       /* call the processing function. Abort further processing if   */
  760.       /* this returns FALSE.                                         */
  761.       /*-------------------------------------------------------------*/
  762.  
  763.       case 1  :
  764.  
  765.         getdirentrys_counter++ ;
  766.  
  767.         direntryblk.load   = fileblk.load ;
  768.         direntryblk.exec   = fileblk.exec ;
  769.         direntryblk.length = fileblk.start ;
  770.         direntryblk.attr   = fileblk.end ;
  771.         direntryblk.name   = dataptr ;
  772.  
  773.         if ( ( fileblk.load & 0xfff00000 ) == 0xfff00000 )
  774.         {
  775.           direntryblk.type = ( fileblk.load & 0x000fff00 ) >> 8 ;
  776.         }
  777.         else
  778.         {
  779.           direntryblk.type = -1 ;
  780.         }
  781.  
  782.         if ( !funcptr(path,&direntryblk) )
  783.         {
  784.           goto badprocess ;
  785.         }
  786.  
  787.         break ;
  788.  
  789.       /*-------------------------------------------------------------*/
  790.       /* Returned value = 2 (directory). Search the queue of         */
  791.       /* subdirectory lists using pointer to directory name as       */
  792.       /* handle. If found then invoke ourselves recursively to       */
  793.       /* process.                                                    */
  794.       /*-------------------------------------------------------------*/
  795.  
  796.       case 2  :
  797.  
  798.         for ( dirwrkptr = dirblkptr->subdirq ;
  799.               dirwrkptr != NULL ;
  800.               dirwrkptr = dirwrkptr->nextptr )
  801.         {
  802.           if ( dirwrkptr->handle == (int)dataptr )
  803.           {
  804.             if ( !extendpath(path,pathlen,dataptr) )
  805.             {
  806.               goto badprocess ;
  807.             }
  808.             if ( !processtree(path,dirwrkptr) )
  809.             {
  810.               goto badprocess ;
  811.             }
  812.           break ;
  813.           }
  814.         }
  815.  
  816.         break ;
  817.  
  818.       /*-------------------------------------------------------------*/
  819.       /* Returned value = -2 (error). Issue error message and abort  */
  820.       /* any further processing.                                     */
  821.       /*-------------------------------------------------------------*/
  822.  
  823.       case _kernel_ERROR :
  824.  
  825.         printf("%s\n",_kernel_last_oserror()->errmess) ;
  826.         beep() ;
  827.         goto badprocess ;
  828.  
  829.       /*-------------------------------------------------------------*/
  830.       /* Other values should not occur. Again, being paranoid, if    */
  831.       /* they do, issue warning message and abort any further        */
  832.       /* processing.                                                 */
  833.       /*-------------------------------------------------------------*/
  834.  
  835.       default :
  836.  
  837.         printf(invalidentry,dataptr) ;
  838.         beep() ;
  839.         goto badprocess ;
  840.     }
  841.     
  842.     /*---------------------------------------------------------------*/
  843.     /* Truncate path to original length.                             */
  844.     /*---------------------------------------------------------------*/
  845.  
  846.     path[pathlen] = '\0' ;
  847.   }
  848.  
  849.   /*-----------------------------------------------------------------*/
  850.   /* After all files processed without error, return TRUE.           */
  851.   /*-----------------------------------------------------------------*/
  852.  
  853.   return TRUE ;
  854.  
  855.   /*-----------------------------------------------------------------*/
  856.   /* Arrive here on error to return FALSE.                           */
  857.   /*-----------------------------------------------------------------*/
  858.  
  859.   badprocess:
  860.  
  861.     path[pathlen] = '\0' ;
  862.     return FALSE ;
  863.  
  864. }
  865.  
  866. /*===================================================================*/
  867. /*                                                                   */
  868. /* extendpath  -  add leafname to path                               */
  869. /* ----------                                                        */
  870. /*                                                                   */
  871. /* This function provides common support to both "buildtree" and     */
  872. /* "processtree" for extending the current path name with a further  */
  873. /* leafname when recursion is required to process a subdirectory.    */
  874. /*                                                                   */
  875. /* It returns TRUE if the path could be extended or FALSE if there   */
  876. /* was not enough room.                                              */
  877. /*                                                                   */
  878. /*===================================================================*/
  879.  
  880. static enum boolean extendpath(
  881.   char *path,                         /* Ptr to current path         */
  882.   int pathlen,                        /* Length of current path      */
  883.   const char *leafname)               /* Ptr to leafname to add      */
  884. {
  885.   /*-----------------------------------------------------------------*/
  886.   /* Executable statements                                           */
  887.   /*                                                                 */
  888.   /* If path would become too long issue error message and take      */
  889.   /* FALSE exit (maxpathlen is defined in "getdirs.h").              */
  890.   /*                                                                 */
  891.   /* Otherwise add period plus leafname to end of path and take      */
  892.   /* TRUE exit.                                                      */
  893.   /*-----------------------------------------------------------------*/
  894.  
  895.   if ( pathlen + 1 + strlen(leafname) > maxpathlen )
  896.   {
  897.     printf(toolong,path) ;
  898.     beep() ;
  899.     return FALSE ;
  900.   }
  901.   
  902.   path[pathlen] = '.' ;
  903.   strcpy(path + pathlen + 1,leafname) ;
  904.   
  905.   return TRUE ;
  906. }
  907.  
  908. /*===================================================================*/
  909. /*                                                                   */
  910. /*  freetree  -  free tree of subdirectory lists                     */
  911. /*  --------                                                         */
  912. /*                                                                   */
  913. /*  This function provides common support to "getdirentrys" and to   */
  914. /*  "buildtree". It frees the tree of directory lists queued off     */
  915. /*  the anchor word provided by the caller. It calls itself          */
  916. /*  recursively to process lists for subdirectories.                 */
  917. /*                                                                   */
  918. /*===================================================================*/
  919.  
  920. static void freetree(
  921.   struct dirblock **subdirq)          /* Ptr to sub directory queue  */
  922. {
  923.   /*-----------------------------------------------------------------*/
  924.   /* Local definitions.                                              */
  925.   /*-----------------------------------------------------------------*/
  926.  
  927.   struct dirblock *dirblkptr ;        /* Directory list block ptr    */
  928.  
  929.   /*-----------------------------------------------------------------*/
  930.   /* Executable statements                                           */
  931.   /*                                                                 */
  932.   /* Run queue of directory lists queued off the anchor word         */
  933.   /* provided by caller, freeing the storage allocated to the lists. */
  934.   /* Invoke ourselves recursively to process subdirectory lists.     */
  935.   /*-----------------------------------------------------------------*/
  936.  
  937.   while ( ( dirblkptr = *subdirq ) != NULL )
  938.   {
  939.     *subdirq = dirblkptr->nextptr ;
  940.     freetree(&dirblkptr->subdirq) ;
  941.     free(dirblkptr) ;
  942.   }
  943. }
  944.  
  945. /*===================================================================*/
  946. /*                                                                   */
  947. /* beep  -  sound two tone beep to indicate error                    */
  948. /* ----                                                              */
  949. /*                                                                   */
  950. /* This function is here simply because I do not like the standard   */
  951. /* beep. Some people may very well think that this is even worse!    */
  952. /*                                                                   */
  953. /*===================================================================*/
  954.  
  955. void beep(void)
  956. {
  957.   /*-----------------------------------------------------------------*/
  958.   /* Local definitions.                                              */
  959.   /*-----------------------------------------------------------------*/
  960.  
  961.   #define Sound_QSchedule   0x401C1   /* Define SWI number           */
  962.  
  963.   #define sound1_delay      0         /* Definition of 1st sound     */
  964.   #define sound1_channel    1
  965.   #define sound1_loudness -10
  966.   #define sound1_pitch     10
  967.   #define sound1_duration   4
  968.  
  969.   #define sound2_delay     15         /* Definition of 2nd sound     */
  970.   #define sound2_channel    1
  971.   #define sound2_loudness  -4
  972.   #define sound2_pitch      0
  973.   #define sound2_duration   7
  974.  
  975.   static _kernel_swi_regs sound1 =    /* SWI regs for 1st sound      */
  976.   {
  977.     sound1_delay,
  978.     0,
  979.     (sound1_loudness << 16) | (sound1_channel),
  980.     (sound1_duration << 16) | (sound1_pitch)
  981.   } ;
  982.  
  983.   static _kernel_swi_regs sound2 =    /* SWI regs for 2nd sound      */
  984.   {
  985.     sound2_delay,
  986.     0,
  987.     (sound2_loudness << 16) | (sound2_channel),
  988.     (sound2_duration << 16) | (sound2_pitch)
  989.   } ;
  990.  
  991.   _kernel_swi_regs dummy ;            /* SWI output regs - ignored   */
  992.  
  993.   /*-----------------------------------------------------------------*/
  994.   /* Executable statements                                           */
  995.   /*                                                                 */
  996.   /* Issue two Sound_QSchedule SWIs to sound two beeps, one after    */
  997.   /* the other, the first of a short duration, the second slightly   */
  998.   /* longer and also quieter and of lower pitch.                     */
  999.   /*-----------------------------------------------------------------*/
  1000.  
  1001.   _kernel_swi(Sound_QSchedule,&sound1,&dummy) ;
  1002.   _kernel_swi(Sound_QSchedule,&sound2,&dummy) ;
  1003. }
  1004.  
  1005. /*===================================================================*/
  1006.